//Net.cpp

#include "stdafx.h"
#include "Net.h"
#include <fstream>

Net::Net()
{
	m_aiBuffer = new byte[MaxBufferSize];
	for(int i = 0; i < 2048; i++) {m_aiBuffer[i] = 0;}
	m_bIsRunning = false;
};

Net::~Net()
{

};

bool Net::Init(World* pWorld)
{
	m_pxWorld = pWorld;
	m_bIsRunning = true;
	m_xLocal = IPAddr::GetLocalDefault();
	m_xLocal.SetPort(GamePort);
	if (m_xSock.Open(m_xLocal))
	{
		printf("Accept socket open at: %s\n", m_xLocal.ToStr().c_str());
		return true;
	}
	else
	{
		printf("Couldn't open accept socket at: %s\n", m_xLocal.ToStr().c_str());
		return false;
	};
};

void Net::Shut()
{
	Msg xMsg;
	xMsg.m_yType = MT_Quit;

	int i;
	for (i = 1; i < m_pxWorld->m_axPlayers.GetSize(); i++)
	{
		IPAddr xTo = m_pxWorld->m_axPlayers[i]->m_xPlayerIp;
		m_xSock.SendTo(xTo, &xMsg, sizeof(xMsg));
	};
};

void Net::Scan()
{
	Msg xMsg;
	xMsg.m_yType = MT_Ping;

	int i;
	for (i = 1; i < 256; i++)
	{
		IPAddr xAddr = IPAddr::GetLocalDefault();
		xAddr.sin_addr.S_un.S_un_b.s_b4 = i;

		if (m_xSock.SendTo(xAddr, &xMsg, sizeof(xMsg)) <= 0)
		{
			printf("Couldn't send ping to: %s\n", xAddr.ToStr().c_str());
		};
	}
};

void Net::Recv()
{
	while(m_xSock.PendingRecv() > 0)
	{
		IPAddr xAddr;
		int iRecv = m_xSock.RecvFrom(xAddr, m_aiBuffer, 2048);
		if(xAddr.GetHost() != m_xLocal.GetHost() && iRecv > 0)
		{
			if(m_aiBuffer[0] == MT_Ping)
			{
				m_pxWorld->AddPlayer(xAddr);

				Msg xMsg;
				xMsg.m_yType = MT_Pong;
				m_xSock.SendTo(xAddr, &xMsg, sizeof(xMsg));

				printf("Received ping message from: %s\n", xAddr.ToStr().c_str());
			}
			else if(m_aiBuffer[0] == MT_Pong)
			{
				m_pxWorld->AddPlayer(xAddr);

				printf("Received pong message from: %s\n", xAddr.ToStr().c_str());
			}
			else if(m_aiBuffer[0] == MT_Quit)
			{
				m_pxWorld->RemovePlayer(xAddr);

				printf("Received quit message from: %s\n", xAddr.ToStr().c_str());
			}
			else if(m_aiBuffer[0] == MT_WorldMsg)
			{
				WorldMsg xMsg;
				memcpy(&xMsg, m_aiBuffer, sizeof(xMsg));
				HandleMsg(xAddr, xMsg);
			};
		};
	};

	//Check for lost connections
	int i;
	int xCurrentTick = ::GetTickCount();
	for (i = 1; i < m_pxWorld->m_axPlayers.GetSize(); i++)
	{
		if ((xCurrentTick-m_pxWorld->m_axPlayers[i]->m_iLastMessageReceived) > TimeOut)
		{
			m_pxWorld->RemovePlayer(m_pxWorld->m_axPlayers[i]->m_xPlayerIp);
		};
	};
};

void Net::Broadcast()
{
	int i;
	for (i = 1; i < m_pxWorld->m_axPlayers.GetSize(); i++)
	{
		int j;
		for (j = 0; j < m_pxWorld->m_axPlayers.GetSize(); j++)
		{
			WorldMsg xMsg;
			xMsg.m_yType = MT_WorldMsg;
			FillMsg(j, &xMsg);

			IPAddr xAddr = m_pxWorld->m_axPlayers[i]->m_xPlayerIp;
			if (m_xSock.SendTo(xAddr, &xMsg, sizeof(xMsg)) <= 0)
			{
				printf("Couldn't send world message to: %s\n", xAddr.ToStr().c_str());
			};
		};
		
	};
};

void Net::HandleMsg(IPAddr& xFrom, WorldMsg& xMsg)
{
	Player* pxPlayer = m_pxWorld->GetPlayer(xFrom);
	if(pxPlayer != NULL)
	{
		if(xMsg.m_iIPAddr == xFrom.GetHost())
		{
			pxPlayer->m_fPositionX = xMsg.m_fPositionX*0.75f + pxPlayer->m_fPositionX*0.25f;
			pxPlayer->m_fPositionY = xMsg.m_fPositionY*0.75f + pxPlayer->m_fPositionY*0.25f;
			pxPlayer->m_fVelocityX = xMsg.m_fVelocityX*0.75f + pxPlayer->m_fVelocityX*0.25f;
			pxPlayer->m_fVelocityY = xMsg.m_fVelocityY*0.75f + pxPlayer->m_fVelocityY*0.25f;
			pxPlayer->m_fAccelerationX = xMsg.m_fAccelerationX*0.75f + pxPlayer->m_fAccelerationX*0.25f;
			pxPlayer->m_fAccelerationY = xMsg.m_fAccelerationY*0.75f + pxPlayer->m_fAccelerationY*0.25f;
			pxPlayer->m_fRotation = xMsg.m_fRotation*0.75f + pxPlayer->m_fRotation*0.25f;
			pxPlayer->m_fThrust = xMsg.m_fThrust*0.75f + pxPlayer->m_fThrust*0.25f;
			pxPlayer->m_fSteering = xMsg.m_fSteering*0.75f + pxPlayer->m_fSteering*0.25f;
			//pxPlayer->m_dwScore = xMsg.m_dwScore;

			pxPlayer->m_dwGemID = xMsg.m_dwGemID;
			pxPlayer->m_fGemPosX = xMsg.m_fGemPosX;
			pxPlayer->m_fGemPosY = xMsg.m_fGemPosY;

			pxPlayer->m_iLastMessageReceived = ::GetTickCount();
		
		};
		m_pxWorld->AddVote(xFrom.GetHost(), xMsg.m_iIPAddr, xMsg.m_dwScore);
	};
};

void Net::FillMsg(int idx, WorldMsg* p_xMsg)
{
	Player* pxPlayer = m_pxWorld->m_axPlayers[idx];
	p_xMsg->m_iNumberOfPlayers = m_pxWorld->m_axPlayers.GetSize();

	p_xMsg->m_iIPAddr = pxPlayer->m_xPlayerIp.GetHost();
	p_xMsg->m_fPositionX = pxPlayer->m_fPositionX;
	p_xMsg->m_fPositionY = pxPlayer->m_fPositionY;
	p_xMsg->m_fVelocityX = pxPlayer->m_fVelocityX;
	p_xMsg->m_fVelocityY = pxPlayer->m_fVelocityY;
	p_xMsg->m_fAccelerationX = pxPlayer->m_fAccelerationX;
	p_xMsg->m_fAccelerationY = pxPlayer->m_fAccelerationY;
	p_xMsg->m_fRotation = pxPlayer->m_fRotation;
	p_xMsg->m_fThrust = pxPlayer->m_fThrust;
	p_xMsg->m_fSteering = pxPlayer->m_fSteering;

	p_xMsg->m_fGemPosX = pxPlayer->m_fGemPosX;
	p_xMsg->m_fGemPosY = pxPlayer->m_fGemPosY;
	p_xMsg->m_dwGemID = pxPlayer->m_dwGemID;

	p_xMsg->m_dwScore = pxPlayer->m_dwScore;
};

void Net::ScanExternals()
{
	std::ifstream stream;
	stream.open("adresses.txt");
	if (!stream.is_open())
	{
		printf("Couldn't open the address text file\n");
	};

	int counter = 0;
	while (!stream.eof())
	{
		char* temp = new char[20];
		stream.getline(temp, 20);
		counter++;
	};

	stream.close();
	stream.open("adresses.txt");
	stream.clear();

	Msg xMsg;
	xMsg.m_yType = MT_Ping;

	for (int i = 0; i < counter; i++)
	{
		char* temp = new char[20];
		stream.getline(temp, 20);

		IPAddr newRemote(const_cast<const char*>(temp));
		int size = 0;
		size = m_xSock.SendTo(newRemote, &xMsg, sizeof(xMsg));
		if (size <= 0)
		{
			printf("Couldn't send ping to: %s\n", newRemote.ToStr().c_str());
		}
	}

	stream.close();
};